Completed
Pull Request — master (#88)
by Alejandro
03:09 queued 01:11
created

build.js ➔ ... ➔ ???   B

Complexity

Conditions 8
Paths 5

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
c 0
b 0
f 0
nc 5
dl 0
loc 38
rs 7.1013
nop 2
1
/* eslint no-console: "off" */
2
3
// Do this as the first thing so that any code reading it knows the right env.
4
process.env.BABEL_ENV = 'production';
5
process.env.NODE_ENV = 'production';
6
7
// Makes the script crash on unhandled rejections instead of silently
8
// ignoring them. In the future, promise rejections that are not handled will
9
// terminate the Node.js process with a non-zero exit code.
10
process.on('unhandledRejection', (err) => {
11
  throw err;
12
});
13
14
// Ensure environment variables are read.
15
require('../config/env');
16
17
const path = require('path');
18
const chalk = require('chalk');
19
const fs = require('fs-extra');
20
const webpack = require('webpack');
21
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
22
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
23
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
24
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
25
const printBuildError = require('react-dev-utils/printBuildError');
26
const AdmZip = require('adm-zip');
27
const paths = require('../config/paths');
28
const config = require('../config/webpack.config.prod');
29
30
const { measureFileSizesBeforeBuild, printFileSizesAfterBuild } = FileSizeReporter;
31
const useYarn = fs.existsSync(paths.yarnLockFile);
32
33
// These sizes are pretty large. We'll warn for bundles exceeding them.
34
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024; // eslint-disable-line
35
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024; // eslint-disable-line
36
37
// Warn and crash if required files are missing
38
if (!checkRequiredFiles([ paths.appHtml, paths.appIndexJs ])) {
39
  process.exit(1);
40
}
41
42
// First, read the current file sizes in build directory.
43
// This lets us display how much they changed later.
44
measureFileSizesBeforeBuild(paths.appBuild)
45
  .then((previousFileSizes) => {
46
    // Remove all content but keep the directory so that
47
    // if you're in it, you don't end up in Trash
48
    fs.emptyDirSync(paths.appBuild);
49
50
    // Merge with the public folder
51
    copyPublicFolder();
52
53
    // Start the webpack build
54
    return build(previousFileSizes);
55
  })
56
  .then(
57
    ({ stats, previousFileSizes, warnings }) => {
58
      if (warnings.length) {
59
        console.log(chalk.yellow('Compiled with warnings.\n'));
60
        console.log(warnings.join('\n\n'));
61
        console.log(
62
          `\nSearch for the ${
63
            chalk.underline(chalk.yellow('keywords'))
64
          } to learn more about each warning.`
65
        );
66
        console.log(
67
          `To ignore, add ${
68
            chalk.cyan('// eslint-disable-next-line')
69
          } to the line before.\n`
70
        );
71
      } else {
72
        console.log(chalk.green('Compiled successfully.\n'));
73
      }
74
75
      console.log('File sizes after gzip:\n');
76
      printFileSizesAfterBuild(
77
        stats,
78
        previousFileSizes,
79
        paths.appBuild,
80
        WARN_AFTER_BUNDLE_GZIP_SIZE,
81
        WARN_AFTER_CHUNK_GZIP_SIZE
82
      );
83
      console.log();
84
85
      const appPackage = require(paths.appPackageJson);
86
87
      const { publicUrl } = paths;
88
      const { publicPath } = config.output;
89
      const buildFolder = path.relative(process.cwd(), paths.appBuild);
90
91
      printHostingInstructions(
92
        appPackage,
93
        publicUrl,
94
        publicPath,
95
        buildFolder,
96
        useYarn
97
      );
98
    },
99
    (err) => {
100
      console.log(chalk.red('Failed to compile.\n'));
101
      printBuildError(err);
102
      process.exit(1);
103
    }
104
  )
105
  .then(zipDist)
106
  .catch((err) => console.error(err));
107
108
// Create the production build and print the deployment instructions.
109
function build(previousFileSizes) {
110
  console.log('Creating an optimized production build...');
111
112
  const compiler = webpack(config);
113
114
  return new Promise((resolve, reject) => {
115
    compiler.run((err, stats) => {
116
      if (err) {
117
        return reject(err);
118
      }
119
120
      const messages = formatWebpackMessages(stats.toJson({}, true));
121
122
      if (messages.errors.length) {
123
        // Only keep the first error. Others are often indicative
124
        // of the same problem, but confuse the reader with noise.
125
        if (messages.errors.length > 1) {
126
          messages.errors.length = 1;
127
        }
128
129
        return reject(new Error(messages.errors.join('\n\n')));
130
      }
131
      if (
132
        process.env.CI &&
133
        (typeof process.env.CI !== 'string' ||
134
          process.env.CI.toLowerCase() !== 'false') &&
135
        messages.warnings.length
136
      ) {
137
        console.log(
138
          chalk.yellow(
139
            '\nTreating warnings as errors because process.env.CI = true.\n' +
140
              'Most CI servers set it automatically.\n'
141
          )
142
        );
143
144
        return reject(new Error(messages.warnings.join('\n\n')));
145
      }
146
147
      return resolve({
148
        stats,
149
        previousFileSizes,
150
        warnings: messages.warnings,
151
      });
152
    });
153
  });
154
}
155
156
function copyPublicFolder() {
157
  fs.copySync(paths.appPublic, paths.appBuild, {
158
    dereference: true,
159
    filter: (file) => file !== paths.appHtml,
160
  });
161
}
162
163
function zipDist() {
164
  const minArgsToContainVersion = 3;
165
166
  // If no version was provided, do nothing
167
  if (process.argv.length < minArgsToContainVersion) {
168
    return;
169
  }
170
171
  const [ , , version ] = process.argv;
172
  const versionFileName = `./dist/shlink-web-client_${version}_dist.zip`;
173
174
  console.log(chalk.cyan(`Generating dist file for version ${chalk.bold(version)}...`));
175
  const zip = new AdmZip();
176
177
  try {
178
    if (fs.existsSync(versionFileName)) {
179
      fs.unlink(versionFileName);
180
    }
181
182
    zip.addLocalFolder('./build', `shlink-web-client_${version}_dist`);
183
    zip.writeZip(versionFileName);
184
    console.log(chalk.green('Dist file properly generated'));
185
  } catch (e) {
186
    console.log(chalk.red('An error occurred while generating dist file'));
187
    console.log(e);
188
  }
189
}
190